/*
 * Copyright (c) 2012 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.libermundi.theorcs.security.tapestry.components;

import java.util.UUID;

import org.apache.commons.validator.routines.EmailValidator;
import org.apache.tapestry5.alerts.AlertManager;
import org.apache.tapestry5.annotations.Component;
import org.apache.tapestry5.annotations.OnEvent;
import org.apache.tapestry5.annotations.Persist;
import org.apache.tapestry5.annotations.Property;
import org.apache.tapestry5.annotations.SessionAttribute;
import org.apache.tapestry5.annotations.SetupRender;
import org.apache.tapestry5.corelib.components.Form;
import org.apache.tapestry5.ioc.Messages;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.libermundi.theorcs.core.CoreConstants;
import org.libermundi.theorcs.core.exceptions.ValueNotFoundException;
import org.libermundi.theorcs.core.tapestry.mixins.RealTimeValidation;
import org.libermundi.theorcs.core.tapestry.model.RealTimeValidationResponse;
import org.libermundi.theorcs.core.tapestry.model.RealTimeValidationResponse.LEVEL;
import org.libermundi.theorcs.core.tapestry.services.configuration.ApplicationConfig;
import org.libermundi.theorcs.core.util.JsonUtils;
import org.libermundi.theorcs.security.SecurityConstants;
import org.libermundi.theorcs.security.model.User;
import org.libermundi.theorcs.security.services.SecurityManager;
import org.libermundi.theorcs.security.services.UserManager;
import org.libermundi.theorcs.security.tapestry.services.GigyaServices;
import org.libermundi.theorcs.security.tapestry.services.UserServices;
import org.slf4j.Logger;

import com.google.common.base.Strings;
import com.google.gson.JsonElement;

public class RegisterForm {
	
	@Inject
	private Logger _logger;
	
	@SessionAttribute(SecurityConstants.SESSION_GIGYA_JSON)
	private JsonElement _gigyaJson;
	
	@SessionAttribute(SecurityConstants.SESSION_REGISTERING_USER)
	private User _registeringUser;
	
	@Inject
	private GigyaServices _gigyaServices;	
	
	@Inject
	private UserManager _userManager;
	
	@Inject
	private Messages _messages;
	
	@Inject
	private UserServices _userServices;
	
	@Inject
	private SecurityManager _securityManager;
	
	@Inject
	private AlertManager _alertManager;
	
	@Inject
	private ApplicationConfig _appConfig;
	
	@Component
	private Form _registerAccountForm;
	
	/*------- Fields for registerAccountForm -------------*/
	@Property
	@Persist
	private String _registerUserName;
	
	@Property
	@Persist
	private String _registerEmail;
	
	@Property
	private String _registerPassword;

	@Property
	private String _registerConfirmPassword;
	
	@Property
	@Persist
	private boolean _registerAcceptToS;
	
	@SetupRender
	public void setupRender(){
		if(_registeringUser == null) {
			_registeringUser = _userManager.getUser();
		}
		if(Strings.isNullOrEmpty(_registerUserName)){
			_registerUserName = _registeringUser.getUsername();
		}
		if(Strings.isNullOrEmpty(_registerEmail)){
			_registerEmail = _registeringUser.getEmail();
		}
		
	}
	
	@OnEvent(value="validate",component="registerAccountForm")
	public void validate(){
		// Check if Username already exists (even if deleted)
		if(!_userManager.isUsernameAvailable(_registerUserName)) {
			_registerAccountForm.recordError(_messages.get("main.registerform.createaccount.error.usernameexists"));
		}
		
		if(!_registerUserName.equals(_registerUserName.replaceAll("\\s", ""))) {
			_registerAccountForm.recordError(_messages.get("main.registerform.createaccount.error.usernamenospace"));
		}
		
		if(!_registerPassword.equals(_registerConfirmPassword)){
			_registerAccountForm.recordError(_messages.get("main.registerform.createaccount.error.passwordnomatch"));
		}
		
		if(_registerAcceptToS == Boolean.FALSE) {
			_registerAccountForm.recordError(_messages.get("main.registerform.createaccount.error.tos"));
		}
	}
	
	@OnEvent(value="success",component="registerAccountForm")
	public String success(){
		_registeringUser.setUsername(_registerUserName);
		_registeringUser.setNickName(_userManager.getUniqueNickName(_registerUserName));
		_registeringUser.setEmail(_registerEmail);
		_registeringUser.setPassword(_registerPassword);
		_registeringUser.setActivationKey(UUID.randomUUID().toString());
		
		_registeringUser.setAccountNonExpired(Boolean.TRUE);
		_registeringUser.setAccountNonLocked(Boolean.TRUE);
		_registeringUser.setCredentialsNonExpired(Boolean.TRUE);
		_registeringUser.setEnabled(Boolean.TRUE);
		_registeringUser.setActive(Boolean.FALSE); // Set to TRUE once clicked in Activation Email
		_registeringUser.setDeleted(Boolean.FALSE);
		
		_userManager.save(_registeringUser);
		
		if(isFromGigya()){
			String gigyaUid;
			try {
				gigyaUid = JsonUtils.getKey(_gigyaJson, "UID");
			} catch (ValueNotFoundException e) {
				_logger.error("GigyaUID not found ! Link association aborted.", e);
				throw new RuntimeException("GigyaUID not found ! Link association aborted.");
			}
			_gigyaServices.notifyRegistration(gigyaUid, _registeringUser, "Register Account");
		}
		
		// At this point we should send an Activation Email to the User
		_userServices.sendActivationEmail(_registeringUser);
		_securityManager.grantRole(_registeringUser, SecurityConstants.ROLE_USER);
		_alertManager.success(_messages.get("register.confirmation"));
		return _appConfig.getString(CoreConstants.HOME_PAGE);
	}
	
	@OnEvent(value=RealTimeValidation.EVENT_NAME,component="registerUserName")
	public RealTimeValidationResponse validateUserName(String username){
		boolean usernameAvailable = _userManager.isUsernameAvailable(username);
		String message = "";
		LEVEL success = LEVEL.SUCCESS;

		if(!usernameAvailable) {
			success = LEVEL.FAILED;
			message = _messages.get("main.registerform.createaccount.error.usernameexists");
		}
		
		if(!username.replaceAll("\\s", "").equals(username)) {
			success = LEVEL.FAILED;
			message = _messages.get("main.registerform.createaccount.error.usernamenospace");
		}
			
		return new RealTimeValidationResponse(success,message);
	}
	
	@OnEvent(value=RealTimeValidation.EVENT_NAME,component="registerEmail")
	public RealTimeValidationResponse validateEmail(String email){
		String message = "";
		LEVEL success = LEVEL.SUCCESS;
		
		EmailValidator v = EmailValidator.getInstance();		
		
		if(!v.isValid(email)) {
			success = LEVEL.FAILED;
			message = _messages.get("main.registerform.createaccount.error.invalidemail");
		}
		
		return new RealTimeValidationResponse(success,message);
	}
	
	/*------- Getters and Setters -------------*/
	public boolean isFromGigya() {
		return _gigyaJson == null ? Boolean.FALSE : Boolean.TRUE;
	}

}
